package persistencia;

import gamebook.Comentario;
import gamebook.MensajeGenerico;
import gamebook.Privado;
import gamebook.Publicacion;
import gamebook.TipoMensaje;
import gamebook.UsuarioGenerico;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class PMensajeGenerico {

    /**
     * Introduce un nuevo mensaje en la base de datos independientemente de qué
     * tipo de mensaje sea. El valor devuelto indica el éxito de la operación
     * @param mensajeGenerico mensaje que queremos guardar
     * @return true o false dependiendo de si se guardó bien o no
     */
    public static boolean darAltaBD(MensajeGenerico mensajeGenerico) {
        boolean resultado = true;         //Si resultado es false es que hubo algún problema
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        //Para el uso de fechas
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            //Conexión con la base de datos
            connection = Persistencia_Conexion.getConnection();
            statement = connection.createStatement();

            //El campo de fecha de nacimiento necesita un tratamiento previo para pasarlo a String
            Date dateFecha = mensajeGenerico.getFecha();
            String stringFecha = dateFormat.format(dateFecha);

            //El campo de foto y especial solo existen si es una publicación
            int intFoto = 0;
            int intEspecial = 0;

            //El campo de publicacion solo existe si es un comentario
            int intPublicacion = 0;

            //El tipo se obtiene del tipo de clase a la que pertenece el mensaje
            int tipo = 0;
            if (mensajeGenerico instanceof Privado) {
                tipo = 1;
            } else if (mensajeGenerico instanceof Publicacion) {
                tipo = 2;
                Publicacion publicacion = (Publicacion) mensajeGenerico;
                //Si es una publicacion puede tener una foto
                if (publicacion.getFoto() != null) {
                    intFoto = publicacion.getFoto().getId();
                } else {
                    intFoto = 0;
                }
                //Si es una publicacion puede ser especial (true=1 / false=0)
                intEspecial = ((Publicacion) mensajeGenerico).isEspecial() ? 1 : 0;
            } else if (mensajeGenerico instanceof Comentario) {
                tipo = 3;
                //Si es un comentario cogemos el id de la publicacion a la que pertenece
                intPublicacion = ((Comentario) mensajeGenerico).getPublicacion().getId();
            }

            //Pasamos el INSERT a la base de datos

            String query = "insert into mensajes ("
                    + "contenido,"
                    + "fecha,"
                    + "id_usuario_origen,"
                    + "id_usuario_destino,"
                    + "id_publicacion,"
                    + "id_foto,"
                    + "especial,"
                    + "tipo) values ("
                    + "'" + mensajeGenerico.getContenido() + "',"
                    + "'" + stringFecha + "',"
                    + mensajeGenerico.getUsuarioOrigen().getId() + ","
                    + mensajeGenerico.getUsuarioDestino().getId() + ","
                    + intPublicacion + ","
                    + intFoto + ","
                    + intEspecial + ","
                    + tipo + ")";


            int registros = statement.executeUpdate(query);

            //Verificamos que se haya actualizado UN registro
            if (registros == 1) {
                //Si hemos introducido el nuevo mensaje, le asignamos el ID con el que se guardó en la base de datos
                resultSet = statement.executeQuery("select id from mensajes order by id desc");
                if (resultSet.next()) {
                    mensajeGenerico.setId(resultSet.getInt("id"));
                }
            } else {
                //Si no se ha introducido el nuevo mensaje por alguna causa, asignamos false a resultado
                resultado = false;
            }
        } catch (Exception ex) {
            resultado = false;
        } finally {
            //Cerramos todo y salimos
            try {
                resultSet.close();
                statement.close();
                connection.close();
            } catch (Exception ex) {
            }
        }

        return resultado;
    }

    /**
     * Actualiza los datos de un mensaje en la base de datos independientemente
     * de qué tipo de mensaje sea. El valor devuelto indica el éxito de la
     * operación, pero esto puede ser por un error o porque los datos que hemos
     * intentado actualizar son iguales a los que había.
     * @param mensajeGenerico mensaje que queremos actualizar
     * @return true o false dependiendo de si se cambio algo o no
     */
    public static boolean actualizarBD(MensajeGenerico mensajeGenerico) {
        boolean resultado = true;         //Si resultado es false es que hubo algún problema
        Connection connection = null;
        Statement statement = null;

        //Para el uso de fechas
        DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

        try {
            //Conexión con la base de datos
            connection = Persistencia_Conexion.getConnection();
            statement = connection.createStatement();

            //El campo de fecha de nacimiento necesita un tratamiento previo para pasarlo a String
            Date dateFecha = mensajeGenerico.getFecha();
            String stringFecha = dateFormat.format(dateFecha);

            //El campo de foto y especial solo existen si es una publicación
            int intFoto = 0;
            int intEspecial = 0;

            //El campo de publicacion solo existe si es un comentario
            int intPublicacion = 0;

            //El tipo se obtiene del tipo de clase a la que pertenece el mensaje
            int tipo = 0;
            if (mensajeGenerico instanceof Privado) {
                tipo = 1;
            } else if (mensajeGenerico instanceof Publicacion) {
                tipo = 2;
                //Si es una publicacion puede tener una foto
                intFoto = ((Publicacion) mensajeGenerico).getFoto().getId();
                //Si es una publicacion puede ser especial (true=1 / false=0)
                intEspecial = ((Publicacion) mensajeGenerico).isEspecial() ? 1 : 0;
            } else if (mensajeGenerico instanceof Comentario) {
                tipo = 3;
                //Si es un comentario cogemos el id de la publicacion a la que pertenece
                intPublicacion = ((Comentario) mensajeGenerico).getPublicacion().getId();
            }

            //Pasamos el UPDATE a la base de datos
            int registros = statement.executeUpdate("update mensajes set "
                    + "contenido='" + mensajeGenerico.getContenido() + "',"
                    + "fecha='" + stringFecha + "',"
                    + "id_usuario_origen=" + mensajeGenerico.getUsuarioOrigen().getId() + ","
                    + "id_usuario_destino=" + mensajeGenerico.getUsuarioDestino().getId() + ","
                    + "id_publicacion=" + intPublicacion + ","
                    + "id_foto=" + intFoto + ","
                    + "especial=" + intEspecial + " "
                    + "where id=" + mensajeGenerico.getId());

            //Verificamos que se haya actualizado UN registro
            if (registros != 1) {
                //Esto puede ser por algún fallo o porque los valores introducidos son iguales a los que había
                resultado = false;
            }

        } catch (Exception ex) {
            //Si hubo error en algun sitio, ponemos resultado a false
            resultado = false;
        } finally {
            //Cerramos todo y salimos
            try {
                statement.close();
                connection.close();
            } catch (Exception ex) {
            }
        }

        return resultado;
    }

    /**
     * Devuelve el MensajeGenerico que tiene como id el parámetro que le pasamos
     * al método. Si no existiese dicho mensaje, la respuesta es un null.
     * @param id id del mensaje requerido
     * @return Devuelve un MensajeGenerico o null si no existe mensaje con dicho id.
     */
    public static MensajeGenerico seleccionarPorIdBD(int id) {
        List<MensajeGenerico> listMensajeGenerico = new ArrayList();
        String sql = "select id, contenido, fecha, id_usuario_origen, id_usuario_destino, id_publicacion, id_foto, especial, tipo from mensajes where id=" + id;
        listMensajeGenerico = seleccionarBD(sql);
        if (listMensajeGenerico.isEmpty()) {
            return null;
        } else {
            return listMensajeGenerico.get(0);
        }
    }

    /**
     * Devuelve el número de mensajes de cierto tipo para cierto destinatario
     * Si no hubiese ninguno devolvería null.
     * @param Usuario el usuario que es destinatario
     * @param TipoMensaje Es un TipoMensaje por si solamente queremos un tipo de mensaje
     * @return List<MensajeGenerico>
     */
    public static int contarPorDestinatarioBD(UsuarioGenerico usuarioGenerico, TipoMensaje tipoMensaje) {
        boolean resultado = true;         //Si resultado es false es que hubo algún problema
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        int total = 0;
        String tipo = "";
        //En caso de que sea algún tipo de mensaje en concreto añadimos un AND al SELECT
        if (tipoMensaje != TipoMensaje.todos) {
            tipo = " and tipo=" + tipoMensaje.getValor();
        }

        try {
            //Conexión con la base de datos
            connection = Persistencia_Conexion.getConnection();
            statement = connection.createStatement();

            //Pasamos el SELECT a la base de datos
            resultSet = statement.executeQuery("select count(id) total from mensajes where id_usuario_destino=" + usuarioGenerico.getId() + tipo);

            //Cogemos del resultSet el valor de la cuenta
            if (resultSet.next()) {
                total = resultSet.getInt("total");
            } else {
                total = 0;
            }


        } catch (Exception ex) {
            //Si hubo error en algun sitio, ponemos resultado a false
            resultado = false;
        } finally {
            //Cerramos todo y salimos
            try {
                resultSet.close();
                statement.close();
                connection.close();
            } catch (Exception ex) {
            }
        }

        //Devolvemos el número total de registros encontrados
        return total;
    }

    public static int contarPorOrigenBD(UsuarioGenerico usuarioGenerico, TipoMensaje tipoMensaje) {
        boolean resultado = true;         //Si resultado es false es que hubo algún problema
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        int total = 0;
        String tipo = "";
        //En caso de que sea algún tipo de mensaje en concreto añadimos un AND al SELECT
        if (tipoMensaje != TipoMensaje.todos) {
            tipo = " and tipo=" + tipoMensaje.getValor();
        }

        try {
            //Conexión con la base de datos
            connection = Persistencia_Conexion.getConnection();
            statement = connection.createStatement();

            //Pasamos el SELECT a la base de datos
            resultSet = statement.executeQuery("select count(id) total from mensajes where id_usuario_origen=" + usuarioGenerico.getId() + tipo);

            //Cogemos del resultSet el valor de la cuenta
            if (resultSet.next()) {
                total = resultSet.getInt("total");
            } else {
                total = 0;
            }


        } catch (Exception ex) {
            //Si hubo error en algun sitio, ponemos resultado a false
            resultado = false;
        } finally {
            //Cerramos todo y salimos
            try {
                resultSet.close();
                statement.close();
                connection.close();
            } catch (Exception ex) {
            }
        }

        //Devolvemos el número total de registros encontrados
        return total;
    }
    
    /**
     * Devuelve una lista de mensajes enviados a cierto destinatario que le pasamos
     * al método. Si no hubiese ninguno devolvería null.
     * @param Usuario el usuario que es destinatario
     * @param TipoMensaje Es un TipoMensaje por si solamente queremos un tipo de mensaje
     * @return List<MensajeGenerico>
     */
    public static List<MensajeGenerico> seleccionarPorDestinatarioBD(UsuarioGenerico usuarioGenerico, TipoMensaje tipoMensaje, int inicio, int fin) {
        List<MensajeGenerico> listMensajeGenerico = new ArrayList();
        String tipo = "";
        //En caso de que sea algún tipo de mensaje en concreto añadimos un AND al SELECT
        if (tipoMensaje != TipoMensaje.todos) {
            tipo = " and tipo=" + tipoMensaje.getValor();
        }
        String sql = "select id, contenido, fecha, id_usuario_origen, id_usuario_destino, id_publicacion, id_foto, especial, tipo from mensajes where id_usuario_destino=" + usuarioGenerico.getId() + tipo + " order by fecha desc limit " + inicio + " , " + fin;
        listMensajeGenerico = seleccionarBD(sql);
        return listMensajeGenerico;
    }

    /**
     * Devuelve una lista de mensajes enviados por cierto destinatario que le pasamos
     * al método. Si no hubiese ninguno devolvería null.
     * @param Usuario el usuario que es origen del mensaje
     * @param TipoMensaje Es un TipoMensaje por si solamente queremos un tipo de mensaje
     * @return List<MensajeGenerico>
     */
    public static List<MensajeGenerico> seleccionarPorOrigenBD(UsuarioGenerico usuarioGenerico, TipoMensaje tipoMensaje, int inicio, int fin) {
        List<MensajeGenerico> listMensajeGenerico = new ArrayList();
        String tipo = "";
        //En caso de que sea algún tipo de mensaje en concreto añadimos un AND al SELECT
        if (tipoMensaje != TipoMensaje.todos) {
            tipo = " and tipo=" + tipoMensaje.getValor();
        }
        String sql = "select id, contenido, fecha, id_usuario_origen, id_usuario_destino, id_publicacion, id_foto, especial, tipo from mensajes where id_usuario_origen=" + usuarioGenerico.getId() + tipo + " order by fecha desc limit " + inicio + " , " + fin;
        listMensajeGenerico = seleccionarBD(sql);
        return listMensajeGenerico;
    }

    /**
     * Devuelve una lista de comentarios enviados sobre cierta publicacion que le pasamos
     * al método. Si no hubiese ninguno devolvería null.
     * @param MensajeGenerico publicacion de la que queremos los comentarios
     * @return List<MensajeGenerico>
     */
    public static List<MensajeGenerico> seleccionarPorPublicacionBD(MensajeGenerico publicacion) {
        List<MensajeGenerico> listMensajeGenerico = new ArrayList();
        //Esto solamente devuelve comentarios que pertenezcan a cierta publicacion
        String sql = "select id, contenido, fecha, id_usuario_origen, id_usuario_destino, id_publicacion, id_foto, especial, tipo from mensajes where tipo=3 and id_publicacion=" + publicacion.getId();
        listMensajeGenerico = seleccionarBD(sql);
        return listMensajeGenerico;
    }

    /**
     * Devuelve el estado de un usuario, que es el último post que hizo el usuario en su muro.
     * @param UsuarioGenerico usuarioGenerico
     * @return MensajeGenerico
     */
    public static MensajeGenerico seleccionarEstadoBD(UsuarioGenerico usuarioGenerico) {
        List<MensajeGenerico> listMensajeGenerico = new ArrayList();
        String sql = "select id, contenido, fecha, id_usuario_origen, id_usuario_destino, id_publicacion, id_foto, especial, tipo from mensajes where tipo=2 and id_usuario_origen=" + usuarioGenerico.getId() + " and id_usuario_destino=" + usuarioGenerico.getId() + " order by fecha desc limit 0,1";
        listMensajeGenerico = seleccionarBD(sql);
        if (listMensajeGenerico.isEmpty()) {
            return null;
        } else {
            return listMensajeGenerico.get(0);
        }
    }

    /**
     * Obtiene una lista de mensajes genéricos según la consulta sql que pasemos
     * @return List<UsuarioGenerico>
     */
    public static List<MensajeGenerico> seleccionarBD(String sql) {
        //Lista de MensajesGenericos que devolveremos
        List<MensajeGenerico> listMensajeGenerico = new ArrayList();

        //Para conectar con la base de datos
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        //Para usar la fecha
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        try {
            //Conectamos con la base de datos
            connection = Persistencia_Conexion.getConnection();
            statement = connection.createStatement();

            resultSet = statement.executeQuery(sql);

            //Mientras haya mensajes que cumplan el criterio SQL los vamos añadiendo
            while (resultSet.next()) {
                //Creamos un mensaje genérico
                MensajeGenerico mensajeGenerico = null;

                if (resultSet.getInt("tipo") == 1) { //Tipo 1 es un mensaje privado
                    Privado privado = new Privado();
                    //Creamos un mensaje privado y metemos las cosas que sean exclusivas de mensaje privado
                    //...no hay ninguna.
                    mensajeGenerico = privado;
                } else if (resultSet.getInt("tipo") == 2) {
                    Publicacion publicacion = new Publicacion(); //Tipo 2 es una publicación
                    //Creamos una publicación y metemos las cosas que sean exclusivas de publicación
                    //Si es una publicacion puede tener una foto
                    publicacion.setFoto(PFoto.seleccionarPorIdBD(resultSet.getInt("id_foto")));
                    //Si es una publicacion puede ser especial (true=1 / false=0)
                    if (resultSet.getInt("especial") == 1) {
                        publicacion.setEspecial(true);
                    } else {
                        publicacion.setEspecial(false);
                    }
                    mensajeGenerico = publicacion;
                } else if (resultSet.getInt("tipo") == 3) {
                    Comentario comentario = new Comentario(); //Tipo 3 es un comentario
                    //Creamos un comentario y metemos las cosas que sean exclusivas de comentario
                    Publicacion publicacionPadre = null;
                    publicacionPadre = (Publicacion) PMensajeGenerico.seleccionarPorIdBD(resultSet.getInt("id_publicacion"));
                    comentario.setPublicacion(publicacionPadre);
                    mensajeGenerico = comentario;
                }

                //Ahora si metemos todo lo que sea común a las tres subclases
                mensajeGenerico.setId(resultSet.getInt("id"));
                mensajeGenerico.setContenido(resultSet.getString("contenido"));
                mensajeGenerico.setUsuarioOrigen(PUsuarioGenerico.seleccionarPorIdBD(resultSet.getInt("id_usuario_origen")));
                mensajeGenerico.setUsuarioDestino(PUsuarioGenerico.seleccionarPorIdBD(resultSet.getInt("id_usuario_destino")));
                mensajeGenerico.setFecha(dateFormat.parse(resultSet.getString("fecha")));

                //Agregamos a la lista y cogemos el siguiente si lo hay
                listMensajeGenerico.add(mensajeGenerico);
            }

        } catch (Exception ex) {
            System.out.println(ex.toString());
        } finally {
            try {
                resultSet.close();
                statement.close();
                connection.close();
            } catch (Exception ex) {
                System.out.println(ex.toString());
            }
        }

        return listMensajeGenerico;
    }

    /**
     * Borra de la base de datos un mensaje y en caso de ser una publicacion, también
     * borrará todos los comentarios asignados a ella.
     * @param MensajeGenerico mensaje que queremos borrar
     * @return boolean true o false según el éxito de la operación
     */
    public static boolean borrarBD(MensajeGenerico mensajeGenerico) {
        boolean resultado = true;         //Si resultado es false es que hubo algún problema
        Connection connection = null;
        Statement statement = null;
        int total = 0;

        try {
            //Conexión con la base de datos
            connection = Persistencia_Conexion.getConnection();
            statement = connection.createStatement();

            //Comprobamos si es una publicacion (tipo=2) para borrar también los comentarios asociados
            if (mensajeGenerico instanceof Publicacion) {
                total += statement.executeUpdate("delete from mensajes where id_publicacion = " + mensajeGenerico.getId());
            }

            //Borramos el mensaje
            total += statement.executeUpdate("delete from mensajes where id = " + mensajeGenerico.getId());

            //En 'total' tendremos el número total de registros eliminados
            if(total==0){
                resultado=false; //Si es cero es que no se ha borrado nada
            }
            
        } catch (Exception ex) {
            //Si hubo error en algun sitio, ponemos resultado a false
            resultado = false;
        } finally {
            //Cerramos todo y salimos
            try {
                statement.close();
                connection.close();
            } catch (Exception ex) {
            }
        }

        //Devolvemos el número total de registros encontrados
        return resultado;
    }
}
